package edu.uwm.cs552;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Observable;
import java.util.Observer;

import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JWindow;
import javax.swing.WindowConstants;
import edu.uwm.cs552.util.JLoggerList;
import edu.uwm.cs552.util.MouseHoverListener;
import edu.uwm.cs552.util.MouseHoverListenerAdapter;

/**
 * Window for playing train game.
 */
public class PlayerFrame extends JFrame {

	/**
	 * Keep Eclipse happy
	 */
	private static final long serialVersionUID = 1L;
	
	private final RailGame game;
	private final Player player;
	
	private JButton move = new JButton("Move");
	private JButton clear = new JButton("Clear Log");
	private JComboBox actions = new JComboBox(PlayerEditAction.values());
	private JCheckBox autoMove = new JCheckBox("Auto-Move");
	private JLabel looking = new JLabel("Looking For: ");
	private JComboBox goods = new JComboBox(Good.allGoods());
	private JButton unload = new JButton("Unload");
	private JButton discard = new JButton("Discard");
	private PlayerStatusPanel playerStatusPanel;
	private GoalCard goal1, goal2, goal3;
	private JWindow hoverWindow;
	private HexBoard hexBoard;

	private PlayerBoardPanel playerPanel;
	
	/**
	 * Create a window for a player (or for the game supervisor).
	 * The game stops when the supervisor window is closed.
	 * @param g game, must not be null
	 * @param p player, may be null for the game supervisor
	 * @param b board being used
	 */
	public PlayerFrame(final RailGame g, final Player p, final HexBoard b) {
		super(p == null ? "Game Control Panel" : ("Player " + p.getIndex()));
		game = g;
		player = p;
		JPanel contentPane = new JPanel();
		this.setContentPane(contentPane);
		contentPane.setLayout(new BorderLayout());
		playerPanel = new PlayerBoardPanel(g,p,b);
		contentPane.add(new JScrollPane(playerPanel),BorderLayout.CENTER);
		JPanel controlPanel = new JPanel();
		contentPane.add(controlPanel,BorderLayout.NORTH);
		hoverWindow = new JWindow();
		hexBoard = b;
		
		controlPanel.add(new ScaleComboBox(playerPanel));
		if (p == null) {
			this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
			g.addObserver(new Observer() {
				private boolean active = true;
				public void update(Observable o, Object arg) {
					if (active) {
						try {
							active = false;
							game.checkTime();
						} finally {
							active = true;
						}
					}
				}
			});
		} else {
			goal1 = GoalCard.generate(b);
			goal2 = GoalCard.generate(b);
			goal3 = GoalCard.generate(b);
			GoalCard[] goals = {goal1,goal2,goal3};
			
			playerStatusPanel = new PlayerStatusPanel(player, player.getTrain(), new CardStatus(goals));
			final JLoggerList loggerList = new JLoggerList(p.getLogger());
			final JScrollPane scrollPane = new JScrollPane(loggerList);
			contentPane.add(scrollPane,BorderLayout.SOUTH);
			contentPane.add(playerStatusPanel,BorderLayout.EAST);
			controlPanel.add(clear);
			controlPanel.add(autoMove);
			controlPanel.add(move);
			controlPanel.add(actions);
			controlPanel.add(looking);
			goods.setSelectedItem(Good.allGoods()[0]);
			controlPanel.add(goods);
			controlPanel.add(unload);
			controlPanel.add(discard);
			this.setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE);

			autoMove.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent arg0) {
					player.setAutoMove(autoMove.isSelected());
				}
			});
			
			move.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent arg0) {
					if (player.hasTime()) player.move(b);
				}
			});
			
			clear.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent arg0) {
					loggerList.clear();
				}
			});
			
			goods.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent arg0) {
					player.setWant((Good) goods.getSelectedItem());
				}
			});
			
			unload.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent arg0) {
					Good[] goods = player.getTrain().getGoods();
					String s = ""; 
					for (int i = 0; i < goods.length; i++) {
						if (goods[i] != null) {
							goods[i].release();
							s = s + goods[i].toString() + ",";
						}
					}
					player.getLogger().info("Unloaded " + s + " from the train");
					player.getTrain().unloadGoods();
				}
			});
			
			discard.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent arg0) {
					if (player.getCards().getSelectedCard() != null) {
						player.addTime(RailGame.DISCARD_TURN_USE);
						player.getCards().replaceSelectedCard(GoalCard.generate(b));
					}
				}
			});		
			
			p.addObserver(new Observer() {
				public void update(Observable o, Object arg) {
					if (o == player) {
						move.setEnabled(player.hasTime());
						
					}
				}
			});
			
			MouseAdapter mouseListener = new MouseAdapter() {
				@Override
				public void mouseDragged(MouseEvent arg0) {
					mouseAction(arg0);
				}
				@Override
				public void mousePressed(MouseEvent arg0) {
					mouseAction(arg0);
				}
			};
			playerPanel.addMouseListener(mouseListener);
			playerPanel.addMouseMotionListener(mouseListener);
			
			MouseHoverListenerAdapter.addHoverListener(playerPanel, new MouseHoverListener() {

				@Override
				public void mouseHoverStart(MouseEvent arg) {
					hoverWindow = new JWindow();
					HexCoordinate hc = HexCoordinate.fromPoint(arg.getPoint(), playerPanel.getScale());
					City city = hexBoard.getCity(hc);
					if (city != null) {
						ArrayList<Good> goods = hexBoard.getGoods(hc);
						Point p = arg.getLocationOnScreen();
						JPanel hoverPanel = new JPanel();
						hoverPanel.setLayout(new BoxLayout(hoverPanel,BoxLayout.PAGE_AXIS));
						JPanel cityPanel = new JPanel();
						JLabel cityLabel = new JLabel(city.getName());
						cityLabel.setSize(cityLabel.getPreferredSize());
						cityPanel.add(cityLabel);
						cityPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
						cityPanel.setSize(cityPanel.getPreferredSize());
						hoverPanel.add(cityPanel);
						if (goods != null) {
							for (Good g : goods) {
								JPanel goodPanel = new JPanel();
								JLabel goodLabel = g.asLabel(true);
								goodLabel.setSize(goodLabel.getPreferredSize());
								goodPanel.add(goodLabel);
								goodPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
								goodPanel.setSize(goodPanel.getPreferredSize());
								hoverPanel.add(goodPanel);
							}
						}
						hoverPanel.setSize(hoverPanel.getPreferredSize());
						hoverWindow.add(hoverPanel);
						hoverWindow.setSize(hoverWindow.getPreferredSize());
						hoverWindow.setLocation(p.x + 1, p.y + 1);
						hoverWindow.setVisible(true);
					}
				}

				@Override
				public void mouseHoverStop(MouseEvent arg) {
					hoverWindow.setVisible(false);
				}
				
			});
		}
		setSize(500,300);
	}
	
	private void mouseAction(MouseEvent arg) {
		PlayerEditAction a = (PlayerEditAction)actions.getSelectedItem();
		a.apply(player, arg.getPoint(), playerPanel.getScale());
	}
}
